package xyz.yuanjilu.controller;

import static xyz.yuanjilu.constant.WebFileConstant.MESSAGE;
import static xyz.yuanjilu.constant.WebFileConstant.CREATE;
import static xyz.yuanjilu.constant.WebFileConstant.DELETE_SUCCESS;
import static xyz.yuanjilu.constant.WebFileConstant.EDIT;
import static xyz.yuanjilu.constant.WebFileConstant.REDIRECT_LIST;
import static xyz.yuanjilu.constant.WebFileConstant.REDIRECT_CREATE;
import static xyz.yuanjilu.constant.WebFileConstant.OPERATION_FAILURE;
import static xyz.yuanjilu.constant.WebFileConstant.OPERATION_SUCCESS;
import static xyz.yuanjilu.constant.WebFileConstant.OPRT;
import static xyz.yuanjilu.constant.WebFileConstant.SAVE_SUCCESS;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import xyz.yuanjilu.controller.form.FileForm;
import xyz.yuanjilu.utils.R;
import xyz.yuanjilu.utils.RRException;
import xyz.yuanjilu.utils.Servlets;
import xyz.yuanjilu.utils.Validations;
import xyz.yuanjilu.utils.file.AntZipUtils;
import xyz.yuanjilu.utils.file.CommonFile;
import xyz.yuanjilu.utils.file.CommonFileFilter;
import xyz.yuanjilu.utils.file.DirCommonFileFilter;
import xyz.yuanjilu.utils.file.FileHandler;
import xyz.yuanjilu.utils.file.FilesEx;
import xyz.yuanjilu.utils.file.LocalFileHandler;
import xyz.yuanjilu.utils.file.PathResolver;


/**
 * WebFileControllerAbstractor
 * 
 * @author liufang
 * 
 */
@RestController
public abstract class WebFileControllerAbstractor {
	protected final Logger logger = LoggerFactory.getLogger(getClass());

	public static final int TEMPLATE = 1;
	public static final int UPLOAD = 2;
	public static final int SITE = 3;

	public static final CommonFileFilter dirFilter = new DirCommonFileFilter();

	protected abstract int getType();

	protected abstract String getBase();

	protected abstract String getDefPath();

	protected abstract String getUrlPrefix();

	protected abstract FileHandler getFileHandler();

	protected abstract boolean isFtp();
	
	@RequestMapping("leftTree")
	protected R leftTree(String parentId) throws IOException {
		
		parentId = parentId == null ? "" : parentId;
		String base = getBase();
		String urlPrefix = getUrlPrefix();
		if (StringUtils.isBlank(parentId)) {
			parentId = base;
		}
		if (!Validations.uri(parentId, base)) {
			throw new RRException("invalidURI");
		}
		FileHandler fileHandler = getFileHandler();
		List<CommonFile> list = fileHandler.listFiles(dirFilter, parentId, urlPrefix);
		R ok = R.ok();
		ok.put("list", list);
		ok.put("type", getType());
		ok.put("isFtp", isFtp());
		return ok;// "core/web_file/web_file_left_tree";
	}
	@RequestMapping("list")
	protected R list(String parentId,String searchName,String page_sort,String page_sort_dir) throws IOException {
		
		parentId = parentId == null ? "" : parentId;
		String base = getBase();
		String defPath = getDefPath();
		String urlPrefix = getUrlPrefix();
		if (StringUtils.isBlank(parentId)) {
			parentId = defPath;
		}
		if (!Validations.uri(parentId, base)) {
			throw new RRException("invalidURI");
		}
		FileHandler fileHandler = getFileHandler();
		CommonFile pp = null;
		if (parentId.length() > base.length()) {
			pp = new CommonFile(CommonFile.getParent(parentId), true);
		}
		List<CommonFile> list = fileHandler.listFiles(searchName, parentId, urlPrefix);
		CommonFile.sort(list, page_sort, page_sort_dir);
		R ok = R.ok();
		if (pp != null) {
			pp.setParent(true);
			list.add(0, pp);
			ok.put("ppId", pp.getId());
		}
		ok.put("parentId", parentId);
		ok.put("list", list);
		ok.put("type", getType());
		ok.put("isFtp", isFtp());
		return ok;// "core/web_file/web_file_list";
	}
	@RequestMapping("info")
	protected R info(String id,String parentId) throws IOException {
		
		String base = getBase();

		String urlPrefix = getUrlPrefix();
		if (!Validations.uri(id, base)) {
			throw new RRException("invalidURI");
		}
		FileHandler fileHandler = getFileHandler();
		CommonFile fileinfo = fileHandler.get(id, urlPrefix);
		R ok = R.ok();
		ok.put("fileinfo", fileinfo);
		return ok;// "core/web_file/web_file_form";
	}
	@RequestMapping("mkdir")
	protected R mkdir(@RequestBody Map<String,String> param, HttpServletRequest request, HttpServletResponse response) throws IOException {
		String parentId = param.get("parentId");
		String dir = param.get("dir");
		parentId = parentId == null ? "" : parentId;
		String base = getBase();

		if (StringUtils.isBlank(parentId)) {
			parentId = base;
		}
		if (!Validations.uri(parentId, base)) {
			throw new RRException("invalidURI");
		}
		FileHandler fileHandler = getFileHandler();
		boolean success = fileHandler.mkdir(dir, parentId);
		if (success) {
			//logService.operation("opr.role.add", parentId + "/" + dir, null, null, request);
			logger.info("mkdir file, name={}.", parentId + "/" + dir);
		}
		R ok = R.ok();
		return ok;
	}
	@RequestMapping("save")
	protected R save(@RequestBody FileForm fileForm) throws IOException {
		/*String parentId = param.get("parentId");
		String name = param.get("name");
		String text = param.get("text");*/
		String parentId = fileForm.getParentId();
		String text = fileForm.getTextDecode64();
		String name = fileForm.getName();
		String base = getBase();

		if (!Validations.uri(parentId, base)) {
			throw new RRException("invalidURI");
		}
		FileHandler fileHandler = getFileHandler();
		fileHandler.store(text, name, parentId);
		logger.info("save file, name={}.", parentId + "/" + name);
		R ok = R.ok();
		return ok;
	}
	@RequestMapping("update")
	protected  R update(@RequestBody FileForm fileForm) throws IOException {
		/*String parentId = param.get("parentId");
		String text = param.get("text");
		String origName = param.get("origName");
		String name = param.get("name");*/
		String parentId = fileForm.getParentId();
		String text = fileForm.getTextDecode64();
		String origName = fileForm.getOrigName();
		String name = fileForm.getName();
		String base = getBase();
		if (!Validations.uri(parentId + "/" + origName, base)) {
			throw new RRException("invalidURI");
		}

		FileHandler fileHandler = getFileHandler();
		if (StringUtils.isNotBlank(text)) {
			fileHandler.store(text, origName, parentId);
		}
		if (!origName.equals(name)) {
			fileHandler.rename(name, parentId + "/" + origName);
		}
		logger.info("update file, name={}.", parentId + "/" + origName);
		R ok = R.ok();
		return ok;
	}
	@RequestMapping("delete")
	protected R delete(@RequestBody Map<String,String> param)
			throws IOException {
		String[] ids = param.get("ids").split(",");
		String base = getBase();

		FileHandler fileHandler = getFileHandler();
		for (int i = 0, len = ids.length; i < len; i++) {
			if (!Validations.uri(ids[i], base)) {
				throw new RRException("invalidURI");
			}
		}
		boolean success = fileHandler.delete(ids);
		if (success) {
			logger.info("delete file success, name={}.", StringUtils.join(ids, ','));
		} else {
			logger.info("delete file failure, name={}.", StringUtils.join(ids, ','));
		}
		R ok = R.ok();
		return ok;
	}
	@RequestMapping("rename")
	protected R rename(@RequestBody Map<String,String> param)
			throws IOException {
		
		String id = param.get("id");
		String name = param.get("name");
		String base = getBase();

		FileHandler fileHandler = getFileHandler();
		if (!Validations.uri(id, base)) {
			throw new RRException("invalidURI");
		}
		boolean success = fileHandler.rename(name, id);
		if (success) {
			//logService.operation("opr.webFile.rename", id, null, null, request);
			logger.info("rename file success, name={}.", id);
		}
		R ok = R.ok();
		return ok;
	}
	@RequestMapping("move")
	protected R move(@RequestBody Map<String,String> param)
			throws IOException {
		
		String[] ids = param.get("ids").split(",");
		String dest = param.get("dest");
		String base = getBase();

		if (!Validations.uri(dest, base)) {
			throw new RRException("invalidURI");
		}
		for (int i = 0, len = ids.length; i < len; i++) {
			if (!Validations.uri(ids[i], base)) {
				throw new RRException("invalidURI");
			}
		}
		FileHandler fileHandler = getFileHandler();
		fileHandler.move(dest, ids);
		logger.info("move file success, name={}.", StringUtils.join(ids, ','));
		R ok = R.ok();
		return ok;
	}
	@RequestMapping("zip")
	protected R zip(@RequestBody Map<String,String> param)
			throws IOException {
		
		FileHandler fileHandler = getFileHandler();
		if (!(fileHandler instanceof LocalFileHandler)) {
			throw new RRException("ftp cannot support ZIP.");
		}
		LocalFileHandler localFileHandler = (LocalFileHandler) fileHandler;
		String[] ids =param.get("ids").split(",");
		String base = getBase();

		File[] files = new File[ids.length];
		for (int i = 0, len = ids.length; i < len; i++) {
			if (!Validations.uri(ids[i], base)) {
				throw new RRException("invalidURI");
			}
			files[i] = localFileHandler.getFile(ids[i]);
		}
		AntZipUtils.zip(files);
		R ok = R.ok();
		return ok;
	}
	@RequestMapping("zipDownload")
	protected void zipDownload(String id, HttpServletResponse response)
			throws IOException {
		
		FileHandler fileHandler = getFileHandler();
		if (!(fileHandler instanceof LocalFileHandler)) {
			throw new RRException("ftp cannot support ZIP.");
		}
		LocalFileHandler localFileHandler = (LocalFileHandler) fileHandler;

		String[] ids =id.split(",");
		String base = getBase();

		File[] files = new File[ids.length];
		for (int i = 0, len = ids.length; i < len; i++) {
			if (!Validations.uri(ids[i], base)) {
				throw new RRException("invalidURI");
			}
			files[i] = localFileHandler.getFile(ids[i]);
		}
		response.reset();  
	    response.setContentType("application/octet-stream; charset=UTF-8");  
		//response.setContentType("application/x-download;charset=UTF-8");
		response.addHeader("Content-disposition", "filename=download_files.zip");
		try {
			AntZipUtils.zip(files, response.getOutputStream());
		} catch (IOException e) {
			logger.error("zip error!", e);
		}
	}
	@RequestMapping("unzip")
	protected R unzip(@RequestBody Map<String,String> param)
			throws IOException {
		
		FileHandler fileHandler = getFileHandler();
		if (!(fileHandler instanceof LocalFileHandler)) {
			throw new RRException("ftp cannot support ZIP.");
		}
		LocalFileHandler localFileHandler = (LocalFileHandler) fileHandler;

		String base = getBase();
		String[] ids = param.get("ids").split(",");
		for (int i = 0, len = ids.length; i < len; i++) {
			if (!Validations.uri(ids[i], base)) {
				throw new RRException("invalidURI");
			}
			File file = localFileHandler.getFile(ids[i]);
			if (AntZipUtils.isZipFile(file)) {
				AntZipUtils.unzip(file, file.getParentFile());
				//logService.operation("opr.webFile.unzip", ids[i], null, null, request);
				logger.info("unzip file, name={}.", ids[i]);
			}
		}

		R ok = R.ok();
		return ok;
	}
	@RequestMapping("upload")
	protected R upload(MultipartFile file, String parentId)
			throws IllegalStateException, IOException {
		
		// parentId = parentId == null ? base : parentId;
		String base = getBase();
		if (!Validations.uri(parentId, base)) {
			throw new RRException("invalidURI");
		}
		FileHandler fileHandler = getFileHandler();
		fileHandler.store(file, parentId);
		//logService.operation("opr.webFile.upload", parentId + "/" + file.getOriginalFilename(), null, null, request);
		logger.info("upload file, name={}.", parentId + "/" + file.getOriginalFilename());
		R ok = R.ok();
		return ok;
	}
	@RequestMapping("zipUpload")
	protected R zipUpload(MultipartFile file, String parentId) throws IOException {
		
		FileHandler fileHandler = getFileHandler();
		if (!(fileHandler instanceof LocalFileHandler)) {
			throw new RRException("ftp cannot support ZIP.");
		}
		LocalFileHandler localFileHandler = (LocalFileHandler) fileHandler;
		String base = getBase();
		// parentId = parentId == null ? base : parentId;

		if (!Validations.uri(parentId, base)) {
			throw new RRException("invalidURI");
		}
		File parentFile = localFileHandler.getFile(parentId);
		File tempFile = FilesEx.getTempFile();
		file.transferTo(tempFile);
		AntZipUtils.unzip(tempFile, parentFile);
		tempFile.delete();

		//logService.operation("opr.webFile.zipUpload", parentId + "/" + file.getOriginalFilename(), null, null, request);
		logger.info("zip upload file, name={}.",parentId + "/" + file.getOriginalFilename());
		R ok = R.ok();
		return ok;
	}

	protected R dir(HttpServletRequest request, HttpServletResponse response, org.springframework.ui.Model modelMap)
			throws IOException {
		
		String parentId = Servlets.getParam(request, "parentId");
		parentId = parentId == null ? "" : parentId;
		String base = getBase();
		String urlPrefix = getUrlPrefix();
		if (StringUtils.isBlank(parentId)) {
			parentId = base;
		}
		if (!Validations.uri(parentId, base)) {
			throw new RRException("invalidURI");
		}

		// 需排除的文件夹
		final String[] ids = Servlets.getParamValues(request, "ids");
		CommonFileFilter filter = new CommonFileFilter() {
			public boolean accept(CommonFile file) {
				// 只显示文件夹，不显示文件
				if (file.isDirectory()) {
					String id = file.getId();
					for (int i = 0, len = ids.length; i < len; i++) {
						if (id.equals(ids[i]) || id.startsWith(ids[i] + "/")) {
							return false;
						}
					}
					return  true;
				}
				return  false;
			}
		};
		FileHandler fileHandler = getFileHandler();
		List<CommonFile> list = fileHandler.listFiles(filter, parentId, urlPrefix);
		// 设置当前目录
		CommonFile parent = new CommonFile(parentId, true);
		parent.setCurrent(true);
		list.add(0, parent);
		// 设置上级目录
		R ok = R.ok();
		if (parentId.length() > base.length()) {
			CommonFile pp = new CommonFile(CommonFile.getParent(parentId), true);
			pp.setParent(true);
			list.add(0, pp);
			ok.put("ppId", pp.getId());
		}
		ok.put("ids", ids);
		ok.put("parentId", parentId);
		ok.put("list", list);
		Servlets.setNoCacheHeader(response);
		return ok;// "core/web_file/choose_dir";
	}

	protected R dirList(HttpServletRequest request, HttpServletResponse response,
			org.springframework.ui.Model modelMap) throws IOException {
		dir(request, response, modelMap);
		R ok = R.ok();
		return ok;// "core/web_file/choose_dir_list";
	}

	@Autowired
	protected PathResolver pathResolver;
}
